<template>
  <div class="flow-container" v-loading="loadingFlag">
    <div class="toolbar" v-if="!props.view">
      <el-button type="success" @click="flowNodeFormWin.openWin(true, null, false)" icon="plus" circle title="添加" />
      <el-button type="success" @click="editNodeData" v-if="selectedNode" icon="Edit" circle title="修改" />
      <el-button type="success" @click="copyNodeData" v-if="selectedNode" icon="CopyDocument" circle title="复制" />
      <el-button @click="deleteSelectedNode" type="danger" v-if="selectedNode" icon="Delete" circle title="删除" />
    </div>
    <div class="last-toolbar" v-if="!props.view">
      <el-link @click="exportImg" style="font-size: 12px;margin-left:10px;" type="info">导出图片</el-link>
      <el-link v-if="nodeId > 1" @click="exportJson" style="font-size: 12px;margin-left:10px;"
        type="info">数据缓存</el-link>
      <el-link v-if="isJsonCache" @click="loadJson" style="font-size: 12px;margin-left:10px;" type="info">加载缓存</el-link>
    </div>
    <VueFlow :nodes="nodes" :max-zoom="1" :min-zoom="0.5" :edges="edges" :nodes-connectable="!props.view"
      @connect="onConnect" @edge-click="onEdgeClick" @node-click="onNodeClick">
      <!-- bind your custom node type to a component by using slots, slot names are always `node-<type>` -->
      <template #node-special="specialNodeProps">
        <special_node v-bind="specialNodeProps" />
      </template>
      <!-- bind your custom edge type to a component by using slots, slot names are always `edge-<type>` -->
      <template #edge-special="specialEdgeProps">
        <special_edge v-bind="specialEdgeProps" />
      </template>
      <MiniMap :node-stroke-width="2" :width="100" :height="100"
        style="background: #f9f9f9; border: 1px dashed rgb(142, 158, 215); border-radius: 8px;" />
    </VueFlow>
  </div>
  <Flow_node_form :click-handle="submitNodeHandle" ref="flowNodeFormWin"></Flow_node_form>
</template>
<script setup lang="ts">
import '@vue-flow/core/dist/style.css';
import '@vue-flow/core/dist/theme-default.css';
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core';
import type { Node, Edge, ViewportTransform } from '@vue-flow/core';
import type { Connection, NodeMouseEvent } from '@vue-flow/core';
import { MiniMap } from '@vue-flow/minimap';
import special_edge from './special_edge.vue';
import special_node from './special_node.vue';
const flowNodeFormWin = ref();
const props = defineProps({
  id: {
    type: String,
    required: false,
  },
  view: {
    type: Boolean,
    required: false,
    default: false,
  },
  linkHandle: {
    type: Function,
    required: false,
  }
});
// 使用 useVueFlow 钩子获取相关方法
const {
  addEdges,
  removeEdges,
  addNodes,
  removeNodes,
  getSelectedNodes, getNodes,
  getEdges, getViewport, setViewport,

} = useVueFlow()

// these are our nodes
const nodes = ref<Node[]>([])

// these are our edges
const edges = ref<Edge[]>([])

const isJsonCache = ref(localStorage.getItem('flowJson') != null);

// 节点计数器
const nodeId = ref(1)

import html2canvas from 'html2canvas';
import Flow_node_form from './flow_node_form.vue';
import type { FlowNodeData } from './type/FlowNodeData';
import Farm2Request from '@/service/remoteRequests/Farm2Request';
import { RequestTypeEnum } from '@/types/commons/RequestTypeEnum';
import type { DataResponse } from '@/types/commons/DataResponse';
import FarmNotice from '@/components/msg/FarmNotice';
const loadingFlag = ref(false);//加载中遮罩
/**
 * 修改节点属性
 */
const editNodeData = () => {
  if (selectedNode.value) {
    flowNodeFormWin.value.openWin(true, selectedNode.value?.data, true)
  }
}
const copyNodeData = () => {
  if (selectedNode.value) {
    flowNodeFormWin.value.openWin(true, selectedNode.value?.data, false)
  }
}


const loadJson = () => {
  const json = localStorage.getItem('flowJson');
  if (json) {
    const data: {
      nodes: Node[];
      edges: Edge[];
      view: ViewportTransform;
    } = JSON.parse(json); // 假设返回 { nodes, edges, viewport }
    nodes.value = data.nodes;
    edges.value = data.edges;
    nodeId.value = Math.max(...data.nodes.map(n => parseInt(n.id)).filter(id => !isNaN(id)), 5) + 1;
    // 恢复 viewport（缩放与位置）
    if (data.view) {
      setViewport(data.view); // ← 使用 setTransform 恢复视图
    }
    localStorage.removeItem('flowJson');
    isJsonCache.value = false;
  }
}
const exportJson = () => {
  localStorage.setItem('flowJson', getDataJson());
  isJsonCache.value = true;
}

// 导出图片为 PNG
const exportImg = () => {
  viewImgHandle((base64: string) => {
    // 创建一个下载链接
    const link = document.createElement('a');
    link.href = base64;
    link.download = `flow-diagram-${new Date().toISOString().slice(0, 10)}.png`; // 文件名：flow-diagram-2025-04-05.png
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link); // 清理 DOM
  })

}

// 当前选中的节点
const selectedNode = computed(() => {
  const selectedNodes = getSelectedNodes.value
  return selectedNodes.length > 0 ? selectedNodes[0] : null
})

// 添加特殊节点
const submitNodeHandle = (nodeData: FlowNodeData, isEdit: boolean) => {
  const newData = {};
  Object.assign(newData, nodeData);
  if (!isEdit) {
    // 获取当前视口的缩放和平移信息
    const viewport = getViewport(); // 当前视图状态，包含缩放与平移信息
    // 计算视窗中心的实际坐标（考虑缩放和平移）
    const centerX = ((window.innerWidth / 3 - viewport.x) / viewport.zoom) - 100;
    const centerY = ((window.innerHeight / 3 - viewport.y) / viewport.zoom) - 100;
    const newNode: Node = {
      id: `${nodeId.value}`,
      type: 'special',
      position: { x: centerX, y: centerY }, // 设置新节点的位置为当前视窗中心
      data: newData,
    }
    // 使用 addNodes 方法添加新节点
    addNodes([newNode])
    nodeId.value = nodeId.value + 1
  } else {
    Object.assign(selectedNode.value?.data, newData);
  }
}

// 处理节点点击事件
const onNodeClick = (nodeMouseEvent: NodeMouseEvent) => {
  //console.log('Node clicked:', nodeMouseEvent.node)
  if (nodeMouseEvent.node.data.link) {
    if (props.linkHandle) {
      props.linkHandle(nodeMouseEvent.node.data.link);
    }
  }
}


// 处理节点连接事件
const onConnect = (connection: Connection) => {
  // 为连线创建一个唯一的ID
  const edgeId = `e${connection.source}-${connection.target}`;
  // 创建新的边对象
  const newEdge: Edge = {
    id: edgeId,
    ...connection,
    animated: false, // 可以设置为true来创建动画效果
    type: connection.source === '3' && connection.target === '4' ? 'special' : 'default' // 根据源和目标节点类型决定边的类型
  }

  // 添加新边到图中
  addEdges([newEdge])
}

// 处理边点击事件，实现删除功能
const onEdgeClick = (edgeMouseEvent: { edge: Edge }) => {
  if (!props.view) {
    const edge = edgeMouseEvent.edge;
    //if (confirm(`确定要删除连接 ${edge.source} 到 ${edge.target} 的连线吗？`)) {
    removeEdges([edge.id]);
  }
}

// 删除选中的节点
const deleteSelectedNode = () => {
  if (selectedNode.value) {
    removeNodes([selectedNode.value.id]);
  }
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// 在 setup 脚本中添加以下代码

// 组件挂载后监听键盘事件
onMounted(() => {
  window.addEventListener('keydown', handleKeyDown);
});

// 组件卸载前移除监听，防止内存泄漏
onUnmounted(() => {
  window.removeEventListener('keydown', handleKeyDown);
});

// 处理键盘事件
const handleKeyDown = (e: KeyboardEvent) => {
  if (['INPUT', 'TEXTAREA'].includes((e.target as HTMLElement).tagName)) {
    return;// 防止输入框等元素触发删除
  }
  if (e.key === 'Delete' || e.key === 'Backspace') {
    e.preventDefault();
    deleteSelectedNode();
  }
};
/**
 * 获得数据
 */
const getDataJson = () => {
  // 获取当前的 nodes、edges 和 viewport（缩放+平移）
  const viewport = getViewport(); // ← 新增：获取当前视图状态
  const flowData = {
    nodes: getNodes.value.map(node => ({ ...node })),
    edges: getEdges.value.map(edge => ({ ...edge })),
    view: viewport,
  };
  const jsonString = JSON.stringify(flowData, null, 2);
  return jsonString;
}
/**
 * 获得预览图
 */
const viewImgHandle = (func: (base64: string) => void) => {
  // 获取 Vue Flow 的画布容器（viewport 或 pane）
  const pane = document.querySelector('.vue-flow__pane') as HTMLElement;
  if (!pane) {
    alert('找不到流程图容器！');
    return;
  }
  // 使用 html2canvas 截图
  html2canvas(pane, {
    backgroundColor: '#ffffff', // 设置背景色（避免透明背景）
    scale: 2, // 提高清晰度
    useCORS: true, // 支持跨域图片
    logging: false, // 关闭日志（可选）
  }).then((canvas) => {
    // 将 canvas 转为 Base64 数据 URL
    const dataURL = canvas.toDataURL('image/png');
    func(dataURL);
  }).catch(err => {
    console.error('截图失败:', err);
    alert('导出图片失败！');
  });
}
/**
 * 获得文字描述
 */
const getTextNote = () => {
  // 获得所有节点的 title，用逗号分隔
  const titles = getNodes.value
    .map(node => node.data?.title)  // 假设 title 在 node.data 中
    .filter(title => title !== undefined && title !== null); // 过滤掉没有 title 的节点
  return titles.join(', ');
}
const setDataJson = (json: string) => {
  if (json) {
    const data: {
      nodes: Node[];
      edges: Edge[];
      view: ViewportTransform;
    } = JSON.parse(json); // 假设返回 { nodes, edges, viewport }
    nodes.value = data.nodes;
    edges.value = data.edges;
    nodeId.value = Math.max(...data.nodes.map(n => parseInt(n.id)).filter(id => !isNaN(id)), 5) + 1;
    // 恢复 viewport（缩放与位置）
    if (data.view) {
      setViewport(data.view); // ← 使用 setTransform 恢复视图
    }
    localStorage.removeItem('flowJson');
    isJsonCache.value = false;
  }
}


//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
onMounted(() => {
  if (props.id && props.view) {
    //获得数据
    Farm2Request.submit("api/wgraph/load", RequestTypeEnum.post, loadingFlag, {
      id: props.id,
    }).then((response: DataResponse) => {
      const data = (response.data as { id: string, dataJson: string });
      setDataJson(data.dataJson);
    }).catch((msg: string) => {
      FarmNotice.byError(msg); // 报错
    });
  }
})
// 暴露方法给父组件
defineExpose({
  //获得数据
  getDataJson,
  //获得预览图
  viewImgHandle,
  //获得文字描述
  getTextNote,
  //加载json
  setDataJson,
});
</script>
<style scoped>
.flow-container {
  width: 100%;
  height: 100%;
  position: relative;
  background-color: #ffffff;
}

.toolbar {
  position: absolute;
  top: 0px;
  right: 0px;
  z-index: 4;
  padding: 10px;
  border-radius: 0px 0px 0px 8px;
  opacity: 0.8;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  background-color: rgb(142, 158, 215);
}

.last-toolbar {
  position: absolute;
  top: 0px;
  left: 0px;
  z-index: 4;
  padding: 4px;
  border-radius: 0px 0px 20px 0px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  padding-bottom: 8px;
  padding-right: 20px;
}

.toolbar:hover {
  opacity: 1;
}

.vue-flow {
  width: 100%;
  height: 100%;
}

/* 样式可以根据需要添加 */
</style>
